;;; hooks.lisp

;;; 

(in-package :gwee)

(defclass hook ()
  ((subscribers :initform nil :accessor hook-subscribers)))

(defgeneric add-hook (hook function))
(defgeneric remove-hook (hook function))
(defgeneric run-hook (hook))
(defgeneric run-hook-with-args (hook &rest args))

(defmethod add-hook ((hook hook) function)
  (pushnew function (hook-subscribers hook) :test 'eql))

(defmethod remove-hook ((hook hook) function)
  (setf (hook-subscribers hook) (delete function (hook-subscribers hook) :test 'eql)))

(defmethod run-hook ((hook hook))
  (mapc 'funcall (hook-subscribers hook)))

(defmethod run-hook-with-args ((hook hook) &rest args)
  (dolist (f (hook-subscribers hook))
    (apply f args)))

(defclass event-hooks-mixin ()
  ((enter       :initform (make-instance 'hook) :accessor enter-hook)
   (leave       :initform (make-instance 'hook) :accessor leave-hook)
   (mouse-press :initform (make-instance 'hook) :accessor mouse-press-hook)
   (mouse-release :initform (make-instance 'hook) :accessor mouse-release-hook)
   (mouse-motion :initform (make-instance 'hook) :accessor mouse-motion-hook)
   (key-press   :initform (make-instance 'hook) :accessor key-press-hook)
   (key-release :initform (make-instance 'hook) :accessor key-release-hook)
   (resize      :initform (make-instance 'hook) :accessor resize-hook)
   (move        :initform (make-instance 'hook) :accessor move-hook)
   (scroll      :initform (make-instance 'hook) :accessor scroll-hook)
   (subviews-hook    :initform (make-instance 'hook) :accessor subviews-hook)))

(defmethod key-press-event :after ((view event-hooks-mixin) key)
  (run-hook-with-args (key-press-hook view) view key))

(defmethod key-release-event :after ((view event-hooks-mixin) key)
  (run-hook-with-args (key-release-hook view) view key))

(defmethod mouse-press-event :after ((view event-hooks-mixin) button x y)
  (run-hook-with-args (mouse-press-hook view) view button x y))

(defmethod mouse-release-event :after ((view event-hooks-mixin) button x y)
  (run-hook-with-args (mouse-release-hook view) view button x y))

(defmethod mouse-motion-event :after ((view event-hooks-mixin) state x y xrel yrel)
  (run-hook-with-args (mouse-motion-hook view) view state x y xrel yrel))
